package work.base.designpattern.single;

/**
 * 单例模式 懒汉式加载
 * 双重检查单例(DCL单例) : 代码优化
 *
 * DCL单例必须要加volatile关键字
 * 原因
 * new一个对象 对应 字节码指令的好几部分 ：(不是汇编指令 是class的字节码指令）
 * 1 new            new分配内存（半初始化状态 成员变量m为0) new
 * 2 invokespecial  成员变量赋值 m = 8;
 * 3 astore_1       栈的引用和堆的对象建立关联 返回对象
 *
 * 如果不使用 volatile 由于指令重排序 2和 3 的顺序反了
 * 第二个线程拿到的对象可能是个半初始化状态的对象  这时候成员变量的值是默认值比如0 变量的值就不对了
 */
public class SingleTest04 {

    /**
     * volatile必加
     */
    private static volatile SingleTest04 INSTANCE; //JIT

    private SingleTest04(){};

    /**
     * 调用 getInstance的时候再去加载
     * 类装载的时候先不new进行实例化
     * @return
     */
    public static SingleTest04 getInstance() {
        // 业务逻辑代码省略
        if(null == INSTANCE) { // Double check
            // synchronized加到里面 而不是整个方法 锁的细一点 锁住整个方法效率较低
            // synchronized内部代码块 需要双重检查
            synchronized (SingleTest04.class) {
                if(null == INSTANCE) {
                    try {
                        Thread.sleep(1);
                    }catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    // 第一个线程返回的对象可能是个半初始化状态
                    INSTANCE = new SingleTest04();
                }
            }
        }
        return INSTANCE;
    }


    public static void main(String[] args) {
        for(int i=0 ; i<100;i++) {
            new Thread(()->{
                System.out.println(SingleTest04.getInstance().hashCode());
            }).start();
        }
    }
}
